<?php
/**
 * paypal支付API接口
 */
class paypalop {
	private $try = 2; //接口调用失败时重试次数

	private $USER = '';//用户363365_1258645654_biz_api1.qq.com
	private $PWD = '';//密码1258645657
	private $VERSION = '';//版本
	private $SIGNATURE = '';//'AJblWzRMwzFTDIdv2DO0szggq0tuAfXCbneDhOEAle5sRtSh5rqZ5vUf '

	private $business = '';//363365_1258645654_biz@qq.com

	private $API_Endpoint = '';//API验证端点https://api-3t.sandbox.paypal.com/nvp

	public $payUrl = ''; //引导页面https://www.sandbox.paypal.com/webscr&cmd=_express-checkout&token=

	private $returnUrl = '';//用户支付完成返回地址
	private $cancelUrl = '';//用户取消支付地址
	private $notifyUrl = '';//paypal服务器回调地址
	
	/**
	 * (支付成功回调地址.用户取消地址.服务端回调地址)
	 */
	public function __construct( $aSet ) {
		foreach( $aSet as $k => $v ) {
			$this->$k = $v;
		}
	}

	public function __init($returnUrl, $cancelUrl, $notifyUrl) {
		$this->returnUrl = $returnUrl;
		$this->cancelUrl = $cancelUrl;
		$this->notifyUrl = $notifyUrl;
	}

	/**
	 * 第一步: 设置订单 调用SetExpressCheckout以设置交易，然后从响应中检索TOKEN
	 * @param String $currencyCode 货币种类,参见 getCurrencyCode 'USD';//美元 或者('GBP', 'EUR', 'JPY', 'CAD', 'AUD')、支付货币代号
	 * @param float $amount 货币数量
	 * @param String $gName 产品名字
	 * @return String '' OR TOKEN
	 */
	public function SetExpressCheckout($currencyCode, $amount, $gName){

		$amount = number_format($amount, 2, '.', '');//支付数量、保留两位小数
		$params = array(
					'METHOD' 		=> 'SetExpressCheckout',
					'CURRENCYCODE'  => $currencyCode,
					'AMT' 			=> $amount,
					'AMOUNT' 		=> $amount,
					'ITEM_NAME' 	=> $gName,
					'ITEM_NUMBER' 	=> 1,
					'ADDROVERRIDE'  => 1,
					'PAYMENTACTION' => 'Sale', //结算类型 Sale 为立即结算
					'RETURNURL'		=> $this->returnUrl,
					'CANCELURL'		=> $this->cancelUrl,
					 );
		$result = $this->sendPost( $params);
		return ( $result[0] == 1) && isset( $result[1]['TOKEN']) ? $result[1]['TOKEN'] : '';
	}

	/**
	 * 获取订单信息，通过此接口可以验证订单的支付情况
	 */
	public function GetExpressCheckoutDetails( $token){
		$params = array(
						'METHOD' => 'GetExpressCheckoutDetails',
						'TOKEN' => $token
						);
		$result = $this->sendPost( $params );
		return $result[0] == 1 ? $result[1] : array();
	}

	/**
	 * 完成支付
	 */
	public function DoExpressCheckoutPayment( $token, $payerId, $invnum, $amount, $gName, $currencyCode = 'USD', $notifyUrl = ''){

		$amount = number_format( $amount,2,'.','');//支付数量、保留两位小数
		$params = array( 'METHOD' 		=> 'DoExpressCheckoutPayment',
						'TOKEN' 		=> $token ,
						'PAYMENTACTION' => 'Sale',
						'AMT'           => $amount ,
						'ITEM_NAME' 	=> $gName,
						'ITEM_NUMBER' 	=> 1,
						'PAYERID' 		=> $payerId,
						'CURRENCYCODE'  => $currencyCode,
						'INVNUM' => $invnum);
		( strlen( $notifyUrl ) > 1 ) && ( $param['NOTIFYURL'] = $notifyUrl );
		$result = $this->sendPost( $params);
		return $result[0] == 1 ? $result[1] : array();
	}

	/**
	 * PayPal支持的货币种类.此只有英文-具体应用因进行语言转换
	 */
	public function getCurrencyCode(){
		$aCurrencyCode = array(
							'USD' => 'U.S. Dollars',//美元、paylal默认的货币种类
							'AUD' => 'Australian Dallars',//澳大利亚Dallars
							'CAD' => 'Canaidan Dollars',//
							'CZK' => 'Czech Korunna',//
							'DKK' => 'Danish Kroner',//
							'EUR' => 'Euros',//
							'HKD' => 'Hong Kong Dollars',//
							'HUF' => 'Hungarian Forint',//
							'NZD' => 'New Zealand Dollars',//
							'NOK' => 'Norwegian Kroner',//
							'PLN' => 'Polish Zlotych',//
							'GBP' => 'Pounds Sterling',//
							'SGD' => 'Singapore Dollars',//
							'SEK' => 'Swedish Kronor',//
							'CHF' => 'Swiss Frances',//
							'JPY' => 'Japan Yen',//
							);
		return $aCurrencyCode;
	}

	/**
	 * 发送请求
	 */
	private function sendPost( $params){
		$params = $this->genParam( $params);
		
		while ($this->try > 0) { //重试
			$this->try--;

			$ch = curl_init();
			curl_setopt($ch, CURLOPT_URL, $this->API_Endpoint);
			curl_setopt($ch, CURLOPT_POST, 1);
			curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
			curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
			$result = curl_exec( $ch);
			$errno = curl_errno( $ch);
			if (( ! $result ) || $errno){ //错误退出
				break;
			}
			$aResult = explode('&', $result);
			$aData = array();
			foreach ((array)$aResult as $row) {
				$aRow = explode('=', $row);
				$aData[strtoupper($aRow[0])] = urldecode( $aRow[1]);
			}
			if ( ( strtoupper($aData['ACK']) === 'SUCCESS' ) || ( strtoupper( $aData['ACK']) === 'SUCCESSWITHWARNING') ) {//调用成功
				break;
			}
			if (($params['METHOD'] === 'SetExpressCheckout') && (! in_array($aData['L_ERRORCODE0'], array(10001, 10102, 10103, 11547)))) {//不在重试范围
				break;
			}
			if (($params['METHOD'] === 'GetExpressCheckoutDetails') && (! in_array($aData['L_ERRORCODE0'],array(10001) ))) {
				break;
			}
			if (($params['METHOD'] === 'DoExpressCheckoutPayment') && (! in_array($aData['L_ERRORCODE0'],array(10001, 10445)) ) ) {
				break;
			}
		}
		return (strtoupper( $aData['ACK']) === 'FAILURE') || $errno ? array(0, $aData) : array(1, $aData);
	}
	/**
	 * 生成参数
	 */
	private function genParam( $params){
		$params['USER'] = $this->USER;
		$params['PWD'] = $this->PWD;
		$params['VERSION'] = $this->VERSION;
		$params['SIGNATURE'] = $this->SIGNATURE;

		foreach ( $params as $key => $value) {
			$aTemp[] = $key . '=' . urlencode( $value);
		}
		return implode('&', $aTemp);//post参数
	}

	/**
	 * 从paypal拿到订单信息
	 * ref:https://www.paypal.com/en_US/ebook/PP_NVPAPI_DeveloperGuide/Appx_fieldreference.html#2050500
	 */
	public function TransactionSearch( $param ) {
		if ( ! $param ) {
			return array();
		}
		$ptime = $param['STARTDATE'] > 0 ? $param['STARTDATE'] : time() - 24 * 60 * 60;
		$param['METHOD'] = 'TransactionSearch';
		$param['STARTDATE'] = date( 'c', $ptime );
		$result = $this->sendPost( $param );

		if ( $result[0] == 1 ) { //拿到交易ID,再次查询
			return $result[1];
		} else {
			return array();
		}
	}

	/**
	 * 从paypal拿到某笔交易的详细信息
	 * ref:https://www.paypal.com/en_US/ebook/PP_NVPAPI_DeveloperGuide/Appx_fieldreference.html#2050500
	 */
	public function GetTransactionDetails( $transid ) {
		if ( ! $transid ) {
			return array();
		}

		$param = array( 'METHOD' => 'GetTransactionDetails',
						'TRANSACTIONID' => $transid );
		$result = $this->sendPost( $param );

		if ( $result[0] == 1 ) { //拿到交易ID,再次查询
			return $result[1];
		} else {
			return array();
		}
	}
}